﻿namespace Devonline.Core;

/// <summary>
/// 静态使用的帮助类方法
/// </summary>
public static class Utility
{
    #region 全局功能方法
    /// <summary>
    /// 延迟方法, 时间间隔单位: 秒, 默认 1 秒
    /// </summary>
    /// <param name="interval"></param>
    public static Task DelayAsync(int interval = AppSettings.UNIT_ONE)
    {
        return Task.Delay(interval * AppSettings.UNIT_THOUSAND);
    }
    /// <summary>
    /// 等待任务完成
    /// </summary>
    /// <param name="condition">等待条件</param>
    /// <param name="interval">判断间隔, 单位: 秒</param>
    /// <returns></returns>
    public static async Task WainingAsync(Func<bool> condition, int interval = AppSettings.UNIT_SECONDS_A_MINUTE)
    {
        while (condition())
        {
            await DelayAsync(interval);
        }
    }
    #endregion

    #region 连续尝试任务直到成功
    /// <summary>
    /// 连续尝试任务直到成功或到达执行次数上限
    /// </summary>
    /// <param name="execute">连续尝试执行的主方法</param>
    /// <param name="maxCount">连续执行的最大次数</param>
    /// <param name="whenException">发生异常时执行的方法</param>
    /// <param name="OnFail">执行结束后执行的方法</param>
    /// <returns>执行结果</returns>
    public static bool Execute(Action execute, int maxCount = AppSettings.UNIT_TEN, Action<Exception>? whenException = default, Action? OnFail = default)
    {
        var index = 0;
        var result = false;
        while (!result && index <= maxCount)
        {
            try
            {
                execute();
                result = true;
                index++;
            }
            catch (Exception ex)
            {
                whenException?.Invoke(ex);
            }
            finally
            {
                if (!result && OnFail is not null)
                {
                    OnFail();
                }
            }
        }

        return result;
    }
    /// <summary>
    /// 连续尝试任务直到成功或到达执行次数上限
    /// </summary>
    /// <param name="execute">连续尝试执行的主方法</param>
    /// <param name="maxCount">连续执行的最大次数</param>
    /// <param name="whenException">发生异常时执行的方法</param>
    /// <param name="OnFail">执行结束后执行的方法</param>
    /// <returns>执行结果</returns>
    public static async Task<bool> ExecuteAsync(Func<Task> execute, int maxCount = AppSettings.UNIT_TEN, Action<Exception>? whenException = default, Func<Task>? OnFail = default)
    {
        var index = 0;
        var result = false;
        while (!result && index <= maxCount)
        {
            try
            {
                await execute();
                result = true;
                index++;
            }
            catch (Exception ex)
            {
                whenException?.Invoke(ex);
            }
            finally
            {
                if (!result && OnFail is not null)
                {
                    await OnFail();
                }
            }
        }

        return result;
    }
    #endregion

    #region 任务执行相关方法
    /// <summary>
    /// 间隔执行任务直到退出, new task need start
    /// </summary>
    /// <param name="exitCondition">执行退出条件</param>
    /// <param name="execute">每一轮执行的主方法</param>
    /// <param name="whenFinally">每一轮执行结束后执行的方法</param>
    /// <param name="whenException">发生异常时执行的方法</param>
    /// <param name="isParallel">是否并行执行</param>
    /// <returns></returns>
    public static Task ExecuteIntervalAsync(Func<bool> exitCondition, Func<Task> execute, Func<Task>? whenFinally = null, Action<Exception>? whenException = null, bool isParallel = false)
    {
        return new Task(async () =>
        {
            while (!exitCondition())
            {
                try
                {
                    if (isParallel)
                    {
                        execute().Start();
                    }
                    else
                    {
                        await execute().ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    whenException?.Invoke(ex);
                }
                finally
                {
                    if (whenFinally == null)
                    {
                        await DelayAsync().ConfigureAwait(false);
                    }
                    else
                    {
                        await whenFinally().ConfigureAwait(false);
                    }
                }
            }
        }, TaskCreationOptions.LongRunning);
    }
    /// <summary>
    /// 间隔执行任务直到退出的泛型版本, 使用当前对象作为参数执行长期间隔循环执行任务, new task need start
    /// </summary>
    /// <typeparam name="T">当前执行参数类型</typeparam>
    /// <param name="t">当前执行参数</param>
    /// <param name="exitCondition">执行退出条件</param>
    /// <param name="execute">每一轮执行的主方法</param>
    /// <param name="whenFinally">每一轮执行结束后执行的方法</param>
    /// <param name="whenException">发生异常时执行的方法</param>
    /// <param name="isParallel">是否并行执行</param>
    /// <returns></returns>
    public static Task ExecuteIntervalAsync<T>(T t, Func<bool> exitCondition, Func<T, Task> execute, Func<Task>? whenFinally = null, Action<Exception>? whenException = null, bool isParallel = false)
    {
        return new Task(async () =>
        {
            while (!exitCondition())
            {
                try
                {
                    if (isParallel)
                    {
                        execute(t).Start();
                    }
                    else
                    {
                        await execute(t).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    whenException?.Invoke(ex);
                }
                finally
                {
                    if (whenFinally == null)
                    {
                        await DelayAsync().ConfigureAwait(false);
                    }
                    else
                    {
                        await whenFinally().ConfigureAwait(false);
                    }
                }
            }
        }, TaskCreationOptions.LongRunning);
    }
    /// <summary>
    /// 间隔执行任务直到退出的泛型版本, 使用当前对象作为参数执行长期间隔循环执行任务, new task need start
    /// </summary>
    /// <typeparam name="T">当前执行参数类型</typeparam>
    /// <param name="t">当前执行参数</param>
    /// <param name="exitCondition">执行退出条件</param>
    /// <param name="execute">每一轮执行的主方法</param>
    /// <param name="whenFinally">每一轮执行结束后执行的方法</param>
    /// <param name="whenException">发生异常时执行的方法</param>
    /// <param name="isParallel">是否并行执行</param>
    /// <returns></returns>
    public static Task ExecuteIntervalAsync<T>(T t, Func<T, bool> exitCondition, Func<T, Task> execute, Func<T, Task>? whenFinally = null, Action<Exception>? whenException = null, bool isParallel = false)
    {
        return new Task(async () =>
        {
            while (!exitCondition(t))
            {
                try
                {
                    if (isParallel)
                    {
                        execute(t).Start();
                    }
                    else
                    {
                        await execute(t).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    whenException?.Invoke(ex);
                }
                finally
                {
                    if (whenFinally == null)
                    {
                        await DelayAsync().ConfigureAwait(false);
                    }
                    else
                    {
                        await whenFinally(t).ConfigureAwait(false);
                    }
                }
            }
        }, TaskCreationOptions.LongRunning);
    }

    /// <summary>
    /// 并行批量执行长期执行的间隔循环执行任务
    /// </summary>
    /// <param name="parallelCount">并发数</param>
    /// <param name="exitCondition">执行退出条件</param>
    /// <param name="execute">每一轮执行的主方法</param>
    /// <param name="whenFinally">每一轮执行结束后执行的方法</param>
    /// <param name="whenException">发生异常时执行的方法</param>
    /// <returns></returns>
    public static ParallelLoopResult ExecuteIntervalParallel(int parallelCount, Func<bool> exitCondition, Func<Task> execute, Func<Task>? whenFinally = null, Action<Exception>? whenException = null) => Parallel.For(0, parallelCount, index => ExecuteIntervalAsync(exitCondition, execute, whenFinally, whenException).Start());
    /// <summary>
    /// 并行批量执行长期执行的间隔循环执行任务的泛型方法, 提供使用 int 类型作为任务数量和编号的参数来启动并行任务
    /// </summary>
    /// <param name="parallelCount">并发数</param>
    /// <param name="exitCondition">执行退出条件</param>
    /// <param name="execute">每一轮执行的主方法</param>
    /// <param name="whenFinally">每一轮执行结束后执行的方法</param>
    /// <param name="whenException">发生异常时执行的方法</param>
    /// <returns></returns>
    public static ParallelLoopResult ExecuteIntervalParallel(int parallelCount, Func<int, bool> exitCondition, Func<int, Task> execute, Func<int, Task>? whenFinally = null, Action<Exception>? whenException = null) => Parallel.For(0, parallelCount, index => ExecuteIntervalAsync(index, exitCondition, execute, whenFinally, whenException).Start());
    /// <summary>
    /// 并行批量执行长期执行的间隔循环执行任务的泛型方法
    /// </summary>
    /// <typeparam name="T">执行对象类型</typeparam>
    /// <param name="args">执行对象</param>
    /// <param name="exitCondition">执行退出条件</param>
    /// <param name="execute">每一轮执行的主方法</param>
    /// <param name="whenFinally">每一轮执行结束后执行的方法</param>
    /// <param name="whenException">发生异常时执行的方法</param>
    /// <returns></returns>
    public static ParallelLoopResult ExecuteIntervalParallel<T>(IEnumerable<T> args, Func<bool> exitCondition, Func<T, Task> execute, Func<Task>? whenFinally = null, Action<Exception>? whenException = null) => Parallel.ForEach(args, arg => ExecuteIntervalAsync(arg, exitCondition, execute, whenFinally, whenException).Start());
    /// <summary>
    /// 并行批量执行长期执行的间隔循环执行任务的泛型方法
    /// </summary>
    /// <typeparam name="T">执行对象类型</typeparam>
    /// <param name="args">执行对象</param>
    /// <param name="exitCondition">执行退出条件</param>
    /// <param name="execute">每一轮执行的主方法</param>
    /// <param name="whenFinally">每一轮执行结束后执行的方法</param>
    /// <param name="whenException">发生异常时执行的方法</param>
    /// <returns></returns>
    public static ParallelLoopResult ExecuteIntervalParallel<T>(IEnumerable<T> args, Func<T, bool> exitCondition, Func<T, Task> execute, Func<T, Task>? whenFinally = null, Action<Exception>? whenException = null) => Parallel.ForEach(args, arg => ExecuteIntervalAsync(arg, exitCondition, execute, whenFinally, whenException).Start());
    #endregion
}